import { Index } from '../../../dbserve';
import { rules } from '../../../utils/rules';
import { dirToTar, tarToDir } from '../../../utils/tar';
import { exec } from 'child_process';
import config from '../../../config';
import { resolve } from 'path';
import { rmDir } from '../../../utils/rmdir';
import { DBclient } from '../../../utils/db';
const list = {
  name: { type: String, default: new Date().getFullYear() },
  tableName: { type: String, default: null },
}
const editlist = {
  id: { required: true, type: Number },
  name: { required: true, type: String }
}
export default class Backups extends Index {
  constructor() {
    super('backups')
  }
  // 修改备份名称
  async edit(req: any, res: any) {
    try {
      const { data, message, error } = rules(req.body, editlist);
      if (error) throw message;
      const { name, id } = data;
      const num = await this._count({ id: { $ne: id }, $or: [{ name }] });
      if (num) throw '名称或地址已存在';
      const bool = await this._edit(data);
      if (bool) res.success(bool, '更新成功');
      else throw '更新失败';
    } catch (error) {
      res.msg(error, 400);
    }
  }
  // 删除备份
  async del(req?: any, res?: any) {
    try {
      let { id } = req.body;
      if (typeof id === 'number' && id) id = [id];
      if (!id.length) throw '删除的数据id不能为空';
      let data: any = await this._find({ id: { $in: id } });
      if (!data.length) throw '目标不存在';
      const paths = data.map((e: any) => resolve(config.backupsDir, './' + e.filename));
      paths.forEach((e: any) => rmDir(e));
      const bool = await this._del(id);
      if (bool) res.success(bool, '删除成功');
      else throw '删除失败';
    } catch (error) {
      console.log(error);

      res.msg(error, 400);
    }
  }

  // 备份整个数据库
  async add(req: any, res: any) {
    try {
      // 验证数据
      const { data, error, message } = rules(req.body, list);
      if (error) throw message;
      const { name } = data;
      const { dbname, dbuser, dbpass, backupsDir } = config;
      const cmdStr = `mongodump  -u ${dbuser} -p ${dbpass}  -d ${dbname} -o ${backupsDir}`;
      const filename = `${config.dbname}-${Date.now()}.tar`;
      exec(cmdStr, { encoding: 'buffer' }, async (error) => {
        if (error) { res.msg('备份失败', 400); throw '备份失败'; }
        // 源目录路径
        let path = resolve(config.backupsDir, config.dbname);
        // 压缩后文件地址
        let target = resolve(config.backupsDir, './' + filename);
        // 开始压缩
        await dirToTar(path, target);
        // 压缩后保存到数据库
        let bool = await this._add({ name, filename, type: 0, tableName: '', createTime: Date.now() });
        res.success(bool, '备份成功');
        // 删除源目录  
        rmDir(path)
      });
    } catch (error) {
      res.msg(error, 400)
    }
  }
  // 获取备份列表
  async list(req?: any, res?: any) {
    try {
      const { page = 1, size = 20, ...query } = req.query;
      const data = await this._query({ page: { page, size }, query });
      res.success(data)
    } catch (error) {
      res.msg(error, 400);
    }
  }
  // 恢复数据库备份
  async reset(req: any, res: any) {
    try {
      let { id = 0 } = req.body;
      if (!id) throw 'id不能为空';
      let data: Array<any> = await this._find({ id });
      if (!data.length) throw '没有找到选中的备份数据';
      let path = resolve(config.backupsDir, './' + data[0].filename);
      let target = resolve(config.backupsDir, config.dbname,);
      tarToDir(path, config.backupsDir);
      let cmdStr = `mongorestore -h ${config.dbhost} -d ${config.dbname} ${target}`;
      exec(cmdStr, { encoding: 'buffer' }, (err) => {
        if (err) throw '恢复失败';
        res.msg('恢复成功');
        // 删除源目录  
        rmDir(target)
      })
    } catch (error) {
      res.msg(error, 400);
    }
  }
  // 获取集合列表
  async tablelist(req: any, res: any) {
    const client = new DBclient();
    const db = await client.getClient();
    const collections = await db.db(config.dbname).collections();
    const tableNames = collections.map((item: any) => item.namespace.replace(config.dbname + '.', ''));
    res.success(tableNames, '')
  }
  // 备份单个集合
  async addOne(req: any, res: any) {
    try {
      const { data } = rules(req.body, list);
      const { name, tableName } = data;
      const { dbname, dbuser, dbpass, backupsDir } = config;
      if (!tableName) throw '要备份的数据表名不能为空';
      const filename = `${tableName}-${Date.now()}.json`;
      const filepath = resolve(backupsDir, './' + filename);
      const cmdStr = `mongoexport  -u ${dbuser} -p ${dbpass}  -d ${dbname} -c ${tableName} -o ${filepath}`;
      exec(cmdStr, { encoding: 'buffer' }, async (error) => {
        if (error) { res.msg('备份失败', 400); return; }
        let bool = await this._add({ name, filename, tableName, type: 1, createTime: Date.now() });
        res.success(bool, '备份成功');
      })
    } catch (error) {
      res.msg(error, 400)
    }
  }
  async resetOne(req: any, res: any) {
    try {
      const { dbname, dbuser, dbpass, backupsDir } = config;
      const { id = 0 } = req.body;
      if (!id) throw 'id不能为空';
      const data: Array<any> = await this._find({ id });
      if (!data.length) throw '没有找到选中的备份数据';
      const { tableName, filename } = data[0];
      const filepath = resolve(backupsDir, './' + filename);
      const cmdStr = `mongoimport  -u ${dbuser} -p ${dbpass}  -d ${dbname} -c ${tableName} --file ${filepath}`;
      exec(cmdStr, { encoding: 'buffer' }, (err) => {
        if (err) throw '恢复失败';
        res.msg('恢复成功');
      })
    } catch (error) {
      res.msg(error, 400);
    }
  }
}